/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.sunspotworld;

import com.sun.spot.peripheral.ChannelBusyException;
import com.sun.spot.peripheral.NoAckException;
import com.sun.spot.peripheral.Spot;
import com.sun.spot.peripheral.radio.IRadiogramProtocolManager;
import com.sun.spot.peripheral.radio.LowPan;
import com.sun.spot.peripheral.radio.RadioPacket;
import com.sun.spot.peripheral.radio.RadioPolicy;
import com.sun.spot.sensorboard.peripheral.LEDColor;
import com.sun.spot.util.IEEEAddress;
import com.sun.spot.util.Utils;
import java.util.Random;
import org.sunspotworld.datawrappers.DataWrapperVector;
import org.sunspotworld.hardware.LEDManager;
import org.sunspotworld.protocols.DataPollProtocol;
import org.sunspotworld.protocols.MyProtocols;
import org.sunspotworld.sensortasks.SensorTask;
import org.sunspotworld.sensortasks.TimeKeeper;

/**
 *
 * @author me
 */
public class PollMobileTask extends SensorTask {
    private static final int PAYLOAD_SIZE = RadioPacket.MIN_PAYLOAD_LENGTH-5;
    
    private static Random random = new Random(new IEEEAddress(System.getProperty("IEEE_ADDRESS")).asLong());
    private static final int RANDOM_BACKOFF = 10;
    private static final int CONSTANT_BACKOFF = 2;
    private static final int BROADCAST_RETRIES = 5;
    private static byte[] buffer = new byte[PAYLOAD_SIZE];
    private long stop = 0;
    private int retries = 0;
    private static boolean heardPoll = false;
    
    public PollMobileTask(long time) {
        super.sampleInterval = time;
    }
    
    private PollMobileTask(long time, long iden) {
        super.sampleInterval = time;
        super.id = iden;
    }
    
    protected SensorTask copy() {
        PollMobileTask task = new PollMobileTask(super.sampleInterval, super.id);
        task.setRepeat(super.repeating);
        return task;
    }
    
    public static void reportPoll() {
        heardPoll = true;
    }

    public void runTask() {
        Spot.getInstance().getRadioPolicyManager().policyHasChanged(TimeKeeper.getInstance(), RadioPolicy.ON);
        stop = TimeKeeper.getInstance().currentTimeMillis() + super.sampleInterval;
        DataPollProtocol.setEnabled(true);
        System.out.println("Listening for polls");
        LEDManager.getInstance().setColor(0, LEDColor.BLUE);
        LEDManager.getInstance().turnOnLED(0);
        /*
        if (Spot.getInstance().getPersistentProperty("Ranging").equals("false")) {
            Utils.sleep(50);
            pollNeighborMobiles();
        }//*/
        heardPoll = true;
        while (/*TimeKeeper.getInstance().currentTimeMillis() < stop &&*/ heardPoll) {
            heardPoll = false;
            Utils.sleep(1000);
        }
        Spot.getInstance().getRadioPolicyManager().policyHasChanged(TimeKeeper.getInstance(), RadioPolicy.OFF);
        DataPollProtocol.setEnabled(false);
        System.out.println("Stopped Listen");
        LEDManager.getInstance().turnOffLED(0);
    }
    
    private void pollNeighborMobiles() {
        long[] addresses = DataWrapperVector.getInstance().getLastNeighbors();
        if (addresses != null) {
            for (int i=0; i<addresses.length; i++) {
                sendPacket(addresses[i]);
                Utils.sleep(500);
            }
        }
    }
    
    private void sendPacket (long toAddress) {
        try {
            LowPan.getInstance().sendWithoutMeshingOrFragmentation(MyProtocols.DATA_TRANSFER, toAddress, buffer, 0, PAYLOAD_SIZE);
            System.out.println("Polling");
        } catch (NoAckException ex) {
            if (retries < BROADCAST_RETRIES && TimeKeeper.getInstance().currentTimeMillis() < stop) {  //if retried less than 5 times and there's enough time left
                retries++;
                sendPacket(toAddress);
            } else {
                ex.printStackTrace();
            }
        } catch (ChannelBusyException ex) {
            if (TimeKeeper.getInstance().currentTimeMillis() + RANDOM_BACKOFF + CONSTANT_BACKOFF< stop) {  //if there's enough time left
                //retry if channel busy
                Utils.sleep(random.nextInt(RANDOM_BACKOFF) + CONSTANT_BACKOFF);  // wait a random amount before retrying
                sendPacket(toAddress);
            }
        }
        retries = 0;  //retries resets after first recursive call of sendPacket falls through to here
    }
}
